<?php

namespace plugin\piecing\app\admin\service;

use support\spark\exception\LogicException;
use support\spark\model\goods\Goods;
use support\spark\model\goods\GoodsRuleExtend;
use plugin\piecing\app\admin\validate\PiecingActivityValidate;
use plugin\piecing\app\model\PiecingActivity;
use plugin\piecing\app\model\PiecingActivityGoods;
use support\Db;
use support\Redis;
use support\spark\exception\ApiException;

class PiecingActivityService
{

    // 活动状态
    protected $activityStatus = [
        1 => '未开启',
        2 => '进行中',
        3 => '已结束'
    ];

    // 拼团的商品规格key %u: activity_id, %u: sku
    protected $piecingKey = 'piecing:%u:%s';

    // 秒杀限制信息key %u: activity_id
    protected $piecingLimitKey = 'piecing_limit:%u';


    /**
     * 秒杀商品列表
     * @param $param
     */
    public function getList($param)
    {
        $seckillTimeModel = new PiecingActivity();
        // 一键关闭过期的
        $seckillTimeModel->updateByWhere([
            'status' => 3, // 已结束
            'update_time' => now()
        ], [
            ['end_time', '<', date('Y-m-d H:i:s')],
            ['status', '=', 1],
            ['is_open', '=', 1]
        ]);

        $limit = $param['limit'];
        $name = $param['name'] ?? '';
        $where = [];
        if (!empty($name)) {
            $where[] = ['name', 'like', '%' . $name . '%'];
        }

        $activityStatus = $this->activityStatus;
        $list = $seckillTimeModel->getPaginateList($where, ['*'], ['id' => 'desc'], [], $limit);
        foreach ($list['data'] as $k => $item) {
            $list['data'][$k]['status_txt'] = $activityStatus[$item['status']];
        }
        return dataReturn(0, 'success', $list);
    }

    /**
     * 检测参数
     * @param $param
     * @return array
     */
    protected function checkParam($param)
    {

        $validate = new PiecingActivityValidate();
        if (!$validate->check($param)) {
            throw new ApiException($validate->getError());
        }

        if ($param['total_buy_num'] < $param['once_buy_num']) {
            throw new ApiException('购买总是限制不得小于单次购买限制');
        }

        // 单规格
        if ($param['goods_rule'] == 1) {

            if (!isset($param['seckill_price']) || empty($param['seckill_price'])) {
                throw new ApiException('选择的规格，拼团价应大于等于0');
            }

            if (!is_numeric($param['stock']) || $param['stock'] < 0) {
                throw new ApiException('选择的规格，限量应该大于等于0');
            }

            if ($param['stock'] > $param['goods_stock']) {
                throw new ApiException('限量库存不得大于商品库存');
            }
        } else { // 多规格

            foreach ($param['final'] as $vo) {
                if (!is_numeric($vo['piecing_price']) || $vo['piecing_price'] < 0) {
                    throw new ApiException('选择的规格，拼团价应大于等于0');
                }

                if (!is_numeric($vo['stock']) || $vo['stock'] < 0) {
                    throw new ApiException('选择的规格，限量应该大于等于0');
                }
                if ($vo['stock'] > $vo['goods_stock']) {
                    throw new ApiException('限量库存不得大于商品库存');
                }
            }
        }
        return true;
    }

    public function addPiecingActivityGoods($param)
    {
        $this->checkParam($param);
        $timeMap = $param['activity_time'];
        Db::beginTransaction();
        try {
            //添加活动
            $activity = [
                'goods_id' => $param['goods_id'],
                'goods_rule' => $param['goods_rule'],
                'pic' => $param['pic'],
                'name' => $param['name'],
                'desc' => $param['desc'],
                'pintuan_time' => $param['pintuan_time'],
                'is_recommend' => 0,
                'start_time' => $timeMap[0],
                'end_time' => $timeMap[1],
                'total_buy_num' => $param['total_buy_num'],
                'once_buy_num' => $param['once_buy_num'],
                'status' => ($param['is_open'] == 1) ? 2 : 1,
                'pintuan_num' => $param['once_buy_num'],
                'is_open' => $param['is_open'],
                'create_time' => now(),
                'update_time' => now()
            ];
            $activityModel = new PiecingActivity();
            $activity_id = $activityModel->insertOne($activity);
            //生成活动商品
            $activityGoods = $piecingPriceArr = [];
            $stock = $piecingPrice = 0;
            $ttl = strtotime($timeMap[1]) - time() + 60 * 5; // 有效期
            // 单规格商品
            if ($param['goods_rule'] == 1) {

                $activityGoods[] = [
                    'activity_id' =>$activity_id,
                    'goods_id' => $param['goods_id'],
                    'sku' => '',
                    'image' => $param['pic'],
                    'goods_price' => $param['goods_price'],
                    'piecing_price' => $param['piecing_price'],
                    'stock' => $param['stock'],
                    'create_time' => now(),
                    'update_time' => now()
                ];

                $stock += $param['stock'];
                $piecingPriceArr = [$param['piecing_price']];
                $key = sprintf($this->piecingKey, $activity_id, '');
                Redis::del($key);
                Redis::set($key, $param['stock']);
                Redis::expire($key, $ttl);
            } else {
                // 多规格商品
                $selectedRules = [];
                foreach ($param['final'] as $vo) {
                    $sku = implode('※', $vo['sku']);
                    $activityGoods[] = [
                        'activity_id' => $activity_id,
                        'sku' => $sku,
                        'goods_id' => $vo['goods_id'],
                        'image' => $vo['image'],
                        'goods_price' => $vo['goods_price'],
                        'piecing_price' => $vo['piecing_price'],
                        'stock' => $vo['stock'],
                        'create_time' => now(),
                        'update_time' => now()
                    ];
                    foreach ($vo['sku'] as $key => $v) {
                        $selectedRules[$key][] = $v;
                    }
                    $stock += $vo['stock'];
                    //获取当前商品规格的最小价格
                    $piecingPriceArr[] = $vo['piecing_price'];
                    $key = sprintf($this->piecingKey, $activity_id, $sku);
                    Redis::del($key);
                    Redis::set($key, $param['stock']);
                    Redis::expire($key, $ttl);
                }

                // 选中的规格
                foreach ($param['rule'] as $key => $vo) {
                    $param['rule'][$key]['item'] = array_values(array_intersect($vo['item'], $selectedRules[$key]));
                }

                $activityModel->updateById([
                    'piecing_goods_rule' => json_encode($param['rule'])
                ], $activity_id);
            }
            // 设置单次购买数量限制
            $limitKey = sprintf($this->piecingLimitKey, $activity_id, $param['goods_id']);
            Redis::del($limitKey);
            Redis::setex($limitKey, $ttl, json_encode([
                'once_buy_num' => $param['once_buy_num'],
                'total_buy_num' => $param['total_buy_num'],
            ]));
            // 写入活动商品
            $seckillActivityGoodsModel = new PiecingActivityGoods();
            $seckillActivityGoodsModel->insertBatch($activityGoods);
            $piecingPrice = min($piecingPriceArr);
             $activityModel->updateById([
                'piecing_price' => $piecingPrice,
            ],$activity_id);
            Db::commit();
        } catch (\Throwable $e) {
            Db::rollBack();
            throw  new  ApiException($e->getMessage() . '|' . $e->getFile() . '|' . $e->getLine());
        }
        return dataReturn(0, '添加成功');
    }

    /**
     * 编辑拼团商品
     * @param $param
     * @return array
     */
    public function editSeckillGoods($param)
    {
        $this->checkParam($param);
        $timeMap = $param['activity_time'];
        Db::beginTransaction();
        try {
            $ttl = strtotime($timeMap[1]) - time() + 60 * 5; // 有效期
            $activityModel = new PiecingActivity();
            $info = $activityModel->with('activityGoods')->where('id', $param['id'])->first();
            // 限制进行中的活动不得更改，防止数据错乱
            if ($info['start_time'] < now() && $info['end_time'] > now()) {
                throw  new  LogicException('该活动时间正在进行中，不可修改');
            }
            $activity = [
                'goods_id' => $param['goods_id'],
                'goods_rule' => $param['goods_rule'],
                'pic' => $param['pic'],
                'name' => $param['name'],
                'desc' => $param['desc'],
                'pintuan_time' => $param['pintuan_time'],
                'is_recommend' => 0,
                'start_time' => $timeMap[0],
                'end_time' => $timeMap[1],
                'total_buy_num' => $param['total_buy_num'],
                'once_buy_num' => $param['once_buy_num'],
                'status' => ($param['is_open'] == 1) ? 2 : 1,
                'pintuan_num' => $param['once_buy_num'],
                'is_open' => $param['is_open'],
                'update_time' => now()
            ];

            $activityModel->updateById($activity, $param['id']);
            $activityGoods = $piecingPriceArr = [];
            $stock = $piecingPrice = 0;
            // 单规格
            if ($param['goods_rule'] == 1) {
                $activityGoods[] = [
                    'activity_id' => $param['id'],
                    'goods_id' => $param['goods_id'],
                    'sku' => '',
                    'image' => $param['pic'],
                    'goods_price' => $param['goods_price'],
                    'piecing_price' => $param['piecing_price'],
                    'stock' => $param['stock'],
                    'create_time' => now(),
                    'update_time' => now()
                ];

                $stock += $param['stock'];
                $piecingPriceArr = [$param['piecing_price']];
                $key = sprintf($this->piecingKey, $info['id'], '');
                Redis::del($key);
                Redis::set($key, $param['stock']);
                Redis::expire($key, $ttl);
            } else { // 多规格
                // 移除旧的key
                foreach ($info['activityGoods'] as $vo) {
                    $key = sprintf($this->piecingKey, $param['id'], $vo['sku']);
                    Redis::del($key);
                }
                // 多规格商品
                $selectedRules = [];
                foreach ($param['final'] as $vo) {
                    $sku = implode('※', $vo['sku']);
                    $activityGoods[] = [
                        'activity_id' => $param['id'],
                        'sku' => $sku,
                        'goods_id' => $vo['goods_id'],
                        'image' => $vo['image'],
                        'goods_price' => $vo['goods_price'],
                        'piecing_price' => $vo['piecing_price'],
                        'stock' => $vo['stock'],
                        'create_time' => now(),
                        'update_time' => now()
                    ];
                    foreach ($vo['sku'] as $key => $v) {
                        $selectedRules[$key][] = $v;
                    }
                    $stock += $vo['stock'];
                    //获取当前商品规格的最小价格
                    $piecingPriceArr[] = $vo['piecing_price'];
                    $key = sprintf($this->piecingKey, $info['id'], $sku);
                    Redis::del($key);
                    Redis::set($key, $param['stock']);
                    Redis::expire($key, $ttl);
                }

                // 选中的规格
                foreach ($param['rule'] as $key => $vo) {
                    $param['rule'][$key]['item'] = array_values(array_intersect($vo['item'], $selectedRules[$key]));
                }

                $activityModel->updateById([
                    'piecing_goods_rule' => json_encode($param['rule'])
                ], $info['id']);
            }


            // 设置单次购买数量限制
            $limitKey = sprintf($this->piecingLimitKey, $info['id'], $param['goods_id']);
            Redis::del($limitKey);
            Redis::setex($limitKey, $ttl, json_encode([
                'once_buy_num' => $param['once_buy_num'],
                'total_buy_num' => $param['total_buy_num'],
            ]));
            $seckillActivityGoodsModel = new PiecingActivityGoods();
            // 删除旧的数据
            $seckillActivityGoodsModel->delByWhere([
                'activity_id' => $param['id']
            ]);
            // 写入活动商品
            $seckillActivityGoodsModel->insertBatch($activityGoods);
            $piecingPrice = min($piecingPriceArr);
           $activityModel->updateById([
                'piecing_price' => $piecingPrice,
            ], $info['id']);
            Db::commit();
        } catch (\Throwable $e) {
            Db::rollback();
            throw  new  ApiException($e->getMessage() . '|' . $e->getFile() . '|' . $e->getLine());
        }

        return dataReturn(0, '编辑成功');
    }

    /**
     * 构建编辑参数
     * @param $activityId
     * @return array
     */
    public function buildEditParam($activityId)
    {
        $activityModel = new PiecingActivity();
        $activityInfo = $activityModel->with(['activityGoods'])->where('id', $activityId)->first();


        // 多规格商品
        if ($activityInfo['goods_rule'] == 2) {
            $goodsRuleExtendModel = new GoodsRuleExtend();
            $ruleList = $goodsRuleExtendModel->getAllList(['goods_id' => $activityInfo['goods_id']]);
            $sku2Stock = [];
            foreach ($ruleList as $vo) {
                $sku2Stock[$vo['sku']] = $vo['stock'];
            }
            foreach ($activityInfo['activityGoods'] as $key => $vo) {
                $activityInfo['activityGoods'][$key]['goods_stock'] = $sku2Stock[$vo['sku']] ?? 0;
            }
        } else { // 单规格商品
            $goodsModel = new Goods();
            $info = $goodsModel->getInfoByWhere(['id' => $activityInfo['goods_id']]);
            foreach ($activityInfo['activityGoods'] as $key => $vo) {
                $activityInfo['activityGoods'][$key]['goods_stock'] = $info['stock'];
            }
        }
        return dataReturn(0, 'success', [
            'jsonInfo' => $activityInfo['activityGoods']
        ]);
    }


    /**
     * 删除秒杀数据
     * @param $id
     */
    public function delSeckill($id)
    {
        $activityModel = new PiecingActivity();
        $info = $activityModel->with('activityGoods')->where('id', $id)->first();
        // 限制进行中的活动不得更改，防止数据错乱
        if ($info['start_time'] < now() && $info['end_time'] > now()) {
            throw  new  LogicException('该活动时间正在进行中，不可修改');
        }

        foreach ($info['activityGoods'] as $vo) {
            $key = sprintf($this->piecingKey, $info['id'], $vo['sku']);
            Redis::del($key);
        }

        $limitKey = sprintf($this->piecingLimitKey, $info['id'], $info['goods_id']);
        Redis::del($limitKey);

        $activityModel->delById($id);
        $seckillActivityModel = new PiecingActivityGoods();
        $seckillActivityModel->delByWhere([
            'activity_id' => $id
        ]);

        return dataReturn(0, '删除成功');
    }


}